#ifndef __HMETIS_IF_H__
#define __HMETIS_IF_H__

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdio>
#include <sstream>

#include <boost/graph/graphviz.hpp>
#include <boost/graph/adjacency_list.hpp>
#include "types.h"
#include "hmetis_if_config.h"
#include "sim_util.h"

static std::string open_temp(std::string path, std::ofstream& f) {
    path += "/XXXXXX";
    std::vector<char> dst_path(path.begin(), path.end());
    dst_path.push_back('\0');

    int fd = mkstemp(&dst_path[0]);
    if(fd != -1) {
        path.assign(dst_path.begin(), --dst_path.end());
        f.open(path.c_str(),
               std::ios_base::trunc | std::ios_base::out);
        close(fd);
    }
    return path;
}

class hmetis_if
{
  public:
    void partition(graph_t &g, int npartitions, std::string prefix)
    {
      if(npartitions == 1) {
        for(int i = 0, nv = num_vertices(g); i < nv; i++) {
          put(vertex_proc, g, i, 0);
        }
        return;
      }
      using namespace boost;
      std::stringstream outfilenamestream;
      outfilenamestream << prefix << ".hmetis." << npartitions;
      std::string outfilename = outfilenamestream.str();
      std::stringstream infilenamestream;
      infilenamestream << outfilename << ".part." << npartitions;
      std::string infilename = infilenamestream.str();
      std::ofstream out(outfilename.c_str(), std::ostream::out);
      out << num_edges(g) << " " << num_vertices(g) << " 11" << std::endl;

      graph_traits<graph_t>::edge_iterator ei, ei_end;
      for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
        Edge e = *ei;
        //out << get(edge_weight, g, e) << " " << source(e, g) << " " << target(e, g) << std::endl;
        out << sim_util::getEdgeMeanDelay(g, e) << " " << (source(e, g)+1) << " " << (target(e, g)+1) << std::endl;
      }
      graph_traits<graph_t>::vertex_iterator vi, vi_end;
      for(tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
        Vertex v = *vi;
        //out << get(vertex_weight, g, v) << std::endl;
        out << sim_util::getVertexMeanDelay(g, v) << std::endl;
      }
      out.close();
      std::stringstream hmetis;
      hmetis << "hmetis " << cfg.get_config_string() << " " << outfilename << " " << npartitions;
      printf("%s\n", hmetis.str().c_str());
      //NOTE: This line runs hMetis through system()
      std::cout << system(hmetis.str().c_str()) << std::endl;
      std::ifstream in(infilename.c_str(), std::istream::in);
      for(int i = 0, nv = num_vertices(g); i < nv; i++) {
        int j;
        in >> j;
        //printf("Part[%d] = %d\n", i, j);
        put(vertex_proc, g, i, j);
      }
      in.close();
    }
    hmetis_if_config cfg;
};

#endif //#ifndef __HMETIS_IF_H__
